package com.sbtr.util;

import cn.hutool.core.util.ZipUtil;
import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**
 * 文件常用操作工具类
 */
public class FileHelper {

    private static Logger logger = Logger.getLogger(String.valueOf(FileHelper.class));

    // 判断文件是否存在
    public static boolean fileExists(String filePath) {
        File file = new File(filePath);
        return file.exists();
    }

    // 读取文件内容并返回字符串
    public static String readTextFile(String filePath) throws IOException, IOException {
        File file = new File(filePath);
        StringBuilder sb = new StringBuilder();
        BufferedReader br = new BufferedReader(new FileReader(file));
        String line;
        while ((line = br.readLine()) != null) {
            sb.append(line).append("\n");
        }
        br.close();
        return sb.toString();
    }

    public static String getDirectoryName(String fileName) {
        File file = new File(fileName);
        return file.getParent();
    }

    // 写入字符串到文件中
    public static void writeTextFile(String filePath, String content) throws IOException {
        File file = new File(filePath);
        FileWriter fw = new FileWriter(file);
        fw.write(content);
        fw.close();
    }

    /**
     * 从指定的URL地址下载文件到本地
     *
     * @param url      要下载的文件的URL地址
     * @param savePath 下载后保存的文件路径
     * @throws IOException 下载文件时可能会抛出IOException异常
     */
    public static void downloadFile(URL url, String savePath) throws IOException {
        try (InputStream in = url.openStream()) {
            Files.copy(in, Paths.get(savePath), StandardCopyOption.REPLACE_EXISTING);
        }
    }

    /**
     * 读取指定目录下的所有文件和子目录
     *
     * @param dirPath 要读取的目录路径
     * @return 目录下所有文件和子目录的File对象列表
     */
    public static List<File> listFiles(String dirPath) {
        List<File> fileList = new ArrayList<>();
        File dir = new File(dirPath);
        if (!dir.exists() || !dir.isDirectory()) {
            return fileList;
        }
        File[] files = dir.listFiles();
        if (files == null || files.length == 0) {
            return null;
        }
        for (File file : files) {
            fileList.add(file);
            if (file.isDirectory()) {
                // 如果是子目录，则递归调用listFiles方法读取子目录下的文件和子目录
                fileList.addAll(listFiles(file.getAbsolutePath()));
            }
        }
        return fileList;
    }

    /**
     * 解压缩指定的zip文件到指定的目录下
     *
     * @param zipFile   要解压缩的zip文件对象
     * @param targetDir 解压缩后保存的目录路径
     * @throws IOException 解压缩文件时可能会抛出IOException异常
     */
    public static void unzipFile(File zipFile, String targetDir) throws IOException {
        try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile))) {
            ZipEntry entry;
            while ((entry = zis.getNextEntry()) != null) {
                String entryName = entry.getName();
                File entryFile = new File(targetDir, entryName);
                if (entry.isDirectory()) {
                    entryFile.mkdirs();
                } else {
                    File parentFile = entryFile.getParentFile();
                    if (!parentFile.exists()) {
                        parentFile.mkdirs();
                    }
                    try (OutputStream out = new FileOutputStream(entryFile)) {
                        byte[] buffer = new byte[1024];
                        int len;
                        while ((len = zis.read(buffer)) != -1) {
                            out.write(buffer, 0, len);
                        }
                    }
                }
            }
        }
    }

    /**
     * 压缩指定目录下的所有文件和子目录为一个zip文件
     *
     * @param dirPath 要压缩的目录路径
     * @param zipPath 压缩后保存的zip文件路径
     * @throws IOException 压缩文件时可能会抛出IOException异常
     */
    public static void zipDirectory(String dirPath, String zipPath) throws IOException {
        File dir = new File(dirPath);
        if (!dir.exists() || !dir.isDirectory()) {
            return;
        }
        try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipPath))) {
            List<File> fileList = listFiles(dirPath);
            for (File file : fileList) {
                String filePath = file.getAbsolutePath();
                String entryName = filePath.substring(dirPath.length() + 1);
                ZipEntry entry = new ZipEntry(entryName);
                if (file.isDirectory()) {
                    entry.setMethod(ZipEntry.STORED);
                    entry.setSize(0);
                    entry.setCrc(0);
                    zos.putNextEntry(entry);
                } else {
                    zos.putNextEntry(entry);
                    try (InputStream in = new FileInputStream(file)) {
                        byte[] buffer = new byte[1024];
                        int len;
                        while ((len = in.read(buffer)) != -1) {
                            zos.write(buffer, 0, len);
                        }
                    }
                }
                zos.closeEntry();
            }
        }
    }

    /**
     * 文件路径替换，得到最终文件存储的相对路径，提供存储给数据库
     *
     * @param fileUrl 文件存储的路径
     * @param itemUrl 项目路径
     * @return
     */
    public static String replaceUrl(String fileUrl, String itemUrl) {
        //解析url
        fileUrl = fileUrl.replace('\\', '/');
        String[] array = itemUrl.replace('\\', '/').split("/");
        //String str1 = array[array.length-1];
        String str1 = array[array.length - 1];

        return fileUrl.substring(fileUrl.indexOf(str1) + str1.length());
    }

    public static String getFileNameWithoutExtension(String fileName) {
        File file = new File(fileName);
        return file.getName().substring(0, file.getName().lastIndexOf("."));
    }

    /**
     * 计算文件大小
     *
     * @param file
     * @return
     */
    public static String getFileSize(File file) {

        String size = "";
        if (file.exists() && file.isFile()) {
            long fileS = file.length();
            DecimalFormat df = new DecimalFormat("#.00");
            if (fileS < 1024) {
                size = df.format((double) fileS) + "BT";
            } else if (fileS < 1048576) {
                size = df.format((double) fileS / 1024) + "KB";
            } else if (fileS < 1073741824) {
                size = df.format((double) fileS / 1048576) + "MB";
            } else {
                size = df.format((double) fileS / 1073741824) + "GB";
            }
        } else if (file.exists() && file.isDirectory()) {
            size = "";
        } else {
            size = "0BT";
        }
        return size;
    }

    // 压缩多个文件
    public static void filesZip(String fileName, List<File> files) throws ZipException, IOException {
        ZipParameters param = new ZipParameters();
        param.setEncryptFiles(true);
        param.setEncryptionMethod(Zip4jConstants.ENC_METHOD_STANDARD);
        param.setPassword(getPassword());
        ZipFile file = new ZipFile(fileName);
        file.setFileNameCharset("GBK");
        for (File f : files) {
            file.addFile(f, param);
        }
    }

    // 压缩文件夹
    public static void fileZip(String fileName, String dirName) throws ZipException, IOException {
        ZipParameters param = new ZipParameters();
        param.setEncryptFiles(true);
        param.setEncryptionMethod(Zip4jConstants.ENC_METHOD_STANDARD);
        param.setPassword(getPassword());
        File dir = new File(dirName);
        ZipFile file = new ZipFile(fileName);
        file.setFileNameCharset("GBK");
        if (dir.isDirectory()) {
            for (File f : dir.listFiles()) {
                file.addFile(f, param);
            }
        } else {
            file.addFile(dir, param);
        }
    }

    // 解压文件来自程序压缩输出的压缩包
    public static void fileUnZip(File source, String target) throws ZipException {
        if (source.exists()) {
            ZipFile srcFile = new ZipFile(source);
//			srcFile.setFileNameCharset("UTF-8");
//			srcFile.setFileNameCharset("gbk");
//			srcFile.setPassword(getPassword()); // 解压无密码
            srcFile.extractAll(target);
        }
    }

    // 解压来自人工压缩的文件
    public static void fileUnZipFromUTF8(File source, String target) throws ZipException {
        if (source.exists()) {
            ZipFile srcFile = new ZipFile(source);
            srcFile.setFileNameCharset("UTF-8");
//			srcFile.setFileNameCharset("gbk");
//			srcFile.setPassword(getPassword()); // 解压无密码
            srcFile.extractAll(target);
        }
    }

    // 解压来自人工压缩的文件
    public static void fileUnZipFromGBK(File source, String target) throws ZipException {
        if (source.exists()) {
            ZipFile srcFile = new ZipFile(source);
            srcFile.setFileNameCharset("gbk");
//			srcFile.setPassword(getPassword()); // 解压无密码
            srcFile.extractAll(target);
        }
    }


    public static void emptyDir(String path) {
        File temp = new File(path);
        if (temp.exists()) {
            File[] tempFiles = temp.listFiles();
            for (File tf : tempFiles) {
                tf.delete();
            }
        } else {
            temp.mkdir();
        }
    }

    /**
     * 清除已解压文件，保留zip压缩文件
     *
     * @param path
     */
    public static void emptyUnFileDir(String path, String zipFileName) {
        File temp = new File(path);
        if (temp.exists()) {
            File[] tempFiles = temp.listFiles();
            for (File tf : tempFiles) {
                String fileName = tf.getName(); //文件名称
                if (!zipFileName.startsWith(fileName)) {
                    tf.delete();
                }
            }
        } else {
            temp.mkdir();
        }
    }

    // 设置压缩文件密码
    public static String getPassword() {
        String pwd = "123456";
        return pwd;
    }

    /**
     * 删除目录及其子目录和文件等
     *
     * @param directory
     */
    public static void delDirAndContents(File directory) {
        if (directory.isDirectory()) {
            File[] files = directory.listFiles();
            for (File file : files) {
                delDirAndContents(file); // 递归删除
            }
        }
        directory.delete(); // 删除最外面目录
    }


    /**
     * 导出File到浏览器
     *
     * @param fileName
     * @param response
     * @param file
     * @throws IOException
     */
    public static void downLoadFileBroswer(String fileName,
                                           HttpServletResponse response, File file) {

        FileInputStream fis = null;
        BufferedInputStream bis = null;
        try {
            response.setHeader("Content-Type", "application/octet-stream;charset=UTF-8");
            response.setHeader("Content-Disposition", "attachment");
            response.setHeader("filename", URLEncoder.encode(fileName, "UTF-8"));
            byte[] buffer = new byte[1024];
            fis = new FileInputStream(file);
            bis = new BufferedInputStream(fis);
            OutputStream os = response.getOutputStream();

            int i = bis.read(buffer);
            while (i != -1) {
                os.write(buffer, 0, i);
                i = bis.read(buffer);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("下载文件出异常！" + e.getMessage());
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 删除目录或文件
     *
     * @param fileName
     * @return 成功返回true ，否则返回flase
     */
    public static boolean deleteFiles(String fileName) {
        File file = new File(fileName);
        if (!file.exists()) {
            return false;
        } else {
            if (file.isFile()) {
                return deleteFile(fileName);
            } else {
                return deleteDirectory(fileName);
            }
        }
    }

    public static Boolean deleteFile(String filePath) {
        File file = new File(filePath);
        if (file.isFile() && file.exists()) {
            return file.delete();
        } else {
            return false;
        }
    }

    /**
     * 递归删除目录
     *
     * @param dir
     * @return
     */
    private static boolean deleteDirectory(String dir) {
        if (dir.endsWith(File.separator)) {
            dir = dir + File.separator;
        }
        File dirFile = new File(dir);
        if (dirFile.exists() && !dirFile.isDirectory()) {
            return false;
        }
        boolean flag = true;
        File[] files = dirFile.listFiles();
        for (int i = 0; i < files.length; i++) {
            if (files[i].isFile()) {
                flag = deleteFile(files[i].getAbsolutePath());
                if (!flag) {
                    break;
                }
            } else {
                flag = deleteDirectory(files[i].getAbsolutePath());
                if (!flag) {
                    break;
                }
            }
        }
        if (!flag) {
            return false;
        }
        if (dirFile.delete()) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 解析SQL文件
     *
     * @param filePath
     * @return
     */
    public static List<String> getSqlFileContent(String filePath) {

        List<String> list = new ArrayList<String>();

        BufferedReader br = null;
        File file = new File(filePath);
        try {
            if (file.exists() && file.isFile()) {
                br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
                String lineText = null;
                while ((lineText = br.readLine()) != null) {
                    System.out.println(lineText);
                    list.add(lineText);
                }
                br.close();
                return list;
            }
        } catch (Exception e1) {
            logger.warning(e1.getMessage());
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return list;
    }


    /**
     * 目录不存在进行创建
     *
     * @param dir
     */
    public static void createDir(String dir) {
        File destFile = new File(dir);
        if (!destFile.exists()) {
            destFile.mkdir();
        }
    }

    /**
     * 文件名称修改
     *
     * @param srcUrl
     * @param destUrl
     * @return
     */
    public static boolean reNameFile(String srcUrl, String destUrl) {
        File srcFile = new File(srcUrl);
        File destFile = new File(destUrl);
        return srcFile.renameTo(destFile);
    }

    /**
     * 复制文件或文件夹
     *
     * @param srcPath  源文件或文件夹路径
     * @param destPath 目标文件或文件夹路径
     * @throws IOException
     */
    public static void copyFile(String srcPath, String destPath) throws IOException {
        FileHelper.createDir(destPath); //  生成
        File srcFile = new File(srcPath);
        File destFile = new File(destPath);
        if (srcFile.isFile()) { // 如果是文件，直接复制
            FileInputStream in = new FileInputStream(srcFile);
            FileOutputStream out = new FileOutputStream(destFile);
            byte[] buffer = new byte[1024];
            int len;
            while ((len = in.read(buffer)) != -1) {
                out.write(buffer, 0, len);
            }
            in.close();
            out.close();
        } else { // 如果是文件夹，递归复制
            if (!destFile.exists()) {
                destFile.mkdir();
            }
            String[] files = srcFile.list();
            for (String file : files) {
                String srcFilePath = srcPath + File.separator + file;
                String destFilePath = destPath + File.separator + file;
                copyFile(srcFilePath, destFilePath);
            }
        }
    }

    /***
     * 传入文件名，得到文件后缀
     * @param fileName
     * @return
     */
    public static String getSuffix(String fileName) {
        int index = fileName.lastIndexOf(".");
        if (index != -1) {
            String suffix = fileName.substring(index);
            return suffix;
        } else {
            return "";
        }
    }

    /**
     * 根据传入文件路径，去除文件路径后的文件，返回目录路径信息
     *
     * @param fileUrl
     * @return
     */
    public static String getDirsUrl(String fileUrl) {
        // 存在后缀，是文件路径
        int index = fileUrl.lastIndexOf("/");
        if (index != -1) {
            fileUrl = fileUrl.substring(0, index);
            return fileUrl;
        } else {
            return fileUrl;
        }
    }

    /**
     * 用于拼接路径，该方法接受任意数量的字符串标识需要拼接的路径片段，
     * 使用File.separator 作为分隔符，并在拼接时会去除重复的分隔符
     *
     * @param paths
     * @return
     */
    public static String buildFIlePath(String... paths) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < paths.length; i++) {
            String path = paths[i];
            boolean isLastPath = i == paths.length - 1;
            if (path.endsWith(File.separator)) {
                path = path.substring(0, paths.length - 1);
            }
            sb.append(path);
            if (!isLastPath) {
                sb.append(File.separator);
            }
        }
        return sb.toString().replaceAll(File.separator + "+", File.separator);
    }

    public static void zipFileList(String modelName, List<File> fileList, HttpServletResponse resp) {
        File zipFile = new File(modelName);

        //压缩多文件
        ZipUtil.zip(zipFile, false, fileList.toArray(new File[0]));

        try (
                InputStream in = new FileInputStream(zipFile);
                OutputStream out = resp.getOutputStream()
        ) {

//            String name = new String(modelName.getBytes("UTF-8"), "ISO-8859-1");
            resp.setContentType("application/octet-stream");
            resp.setHeader("Content-Disposition", "attachment;" + " filename=" + modelName);
            int byteRead = 0;
            byte[] buffer = new byte[512];
            while ((byteRead = in.read(buffer)) != -1) {
                out.write(buffer, 0, byteRead);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        //删除生成
        zipFile.delete();
    }
}
